using System;
using Microsoft.Surface;
using Microsoft.Surface.Presentation;
using Microsoft.Surface.Presentation.Controls;
using Microsoft.Surface.Presentation.Input;
using SurfaceInteraction.UI.Surface.Services;
using System.Windows.Threading;
using System.Windows;
using System.Windows.Media;
using SurfaceInteraction.UI.Surface.Helper;
using SurfaceInteraction.UI.Surface.Dispenser;
using System.Windows.Input;

namespace SurfaceInteraction.UI.Surface
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class Shell : SurfaceWindow
    {
        /// <summary>
        /// Default constructor.
        /// </summary>
        public Shell()
        {
            InitializeComponent();

            // Add handlers for window availability events
            AddWindowAvailabilityHandlers();

            HostService.DownloadRequestEvent += new MetaData.DownloadRequestEventHandler(HostService_DownloadRequestEvent);
            this.Loaded += new RoutedEventHandler(Shell_Loaded);
            //this.TouchDown += new EventHandler<TouchEventArgs>(Shell_TouchDown);



            

            for (int i = 0; i < 256; i++)
            {
                TagVisualizationDefinition tagDefinition = new TagVisualizationDefinition();
                //ByteTagVisualizationDefinition tagDefinition = new ByteTagVisualizationDefinition();
                tagDefinition.Value = (byte)i;
                tagDefinition.Source = new Uri("GeneralTagVisualization.xaml", UriKind.Relative);
                tagDefinition.MaxCount = 1;
                // These values are used when creating a TagVisualization object.
                // The TagVisualization object has these properties also. They can
                // be changed during a TagVisualizer event if needed.
                //tagDefinition.LostTagTimeout = 2000.0; // 2 seconds
                //tagDefinition.OrientationOffsetFromTag = 5.0;
                //tagDefinition.PhysicalCenterOffsetFromTag = new Vector(2, 0);
                //tagDefinition.TagRemovedBehavior = TagRemovedBehavior.Fade;
                //tagDefinition.UsesTagOrientation = true;
                // Add the definition to the collection.
                tagVisualizer.Definitions.Add(tagDefinition);
            }

          
        }

        void Shell_Loaded(object sender, RoutedEventArgs e)
        {
            ImageDispenser dispenser = new ImageDispenser();

            foreach (string image in dispenser.Images)
            {
                ScatterViewItem svi = new ScatterViewItem(); 
                svi.Content = new Content() { DataContext = image };
                svi.MinHeight = 200;
                svi.MinWidth = 200;
                svi.MaxHeight = 1000;
                svi.MaxWidth = 1000;
                sv.Items.Add(svi);
            }
        }

        
        /// <summary>
        /// Occurs when the window is about to close. 
        /// </summary>
        /// <param name="e"></param>
        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);

            // Remove handlers for window availability events
            RemoveWindowAvailabilityHandlers();
        }

        void HostService_DownloadRequestEvent(object sender, MetaData.FileExchangeRequestEventArgs e)
        {
            // a download request from the handled device is arrived
            // now we have to check witch content is under the divice, get the correspondig image and send to the service.

            //get the scatterview
            this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                    (System.Action)(() =>
                    {
                        TagVisualization tag = null;
                        foreach (TagVisualization t in tagVisualizer.ActiveVisualizations)
                        {
                            if (t.VisualizedTag.Value == e.Id)
                            {
                                tag = t;
                            }
                        }

                        if (tag == null)
                            return;
                        
                        // get the position of the control without rotation
                        Point thisA = new Point((tag.Center.X - (this.ActualWidth / 2)), (tag.Center.Y - (this.ActualHeight / 2)));
                        Point thisB = new Point((tag.Center.X + (this.ActualWidth / 2)), (tag.Center.Y - (this.ActualHeight / 2)));
                        Point thisC = new Point((tag.Center.X + (this.ActualWidth / 2)), (tag.Center.Y + (this.ActualHeight / 2)));
                        Point thisD = new Point((tag.Center.X - (this.ActualWidth / 2)), (tag.Center.Y + (this.ActualHeight / 2)));

                        // get the position of the rotated control with some math calculation
                        Point thisA1 = thisA.GetRotatedPoint(tag.Orientation, this.ActualWidth, this.ActualHeight);
                        Point thisB1 = thisB.GetRotatedPoint(tag.Orientation, this.ActualWidth, this.ActualHeight);
                        Point thisC1 = thisC.GetRotatedPoint(tag.Orientation, this.ActualWidth, this.ActualHeight);
                        Point thisD1 = thisD.GetRotatedPoint(tag.Orientation, this.ActualWidth, this.ActualHeight);

                        Rect r1 = new Rect(thisA1, thisC1);
                        
                        

                        foreach (ScatterViewItem item in sv.Items)
                        {
                            if (item.Content is Content)
                            {

                                //check if the item is under 

                                // get the position of the control without rotation
                                Point itemA = new Point((item.Center.X - (item.ActualWidth / 2)), (item.Center.Y - (item.ActualHeight / 2)));
                                Point itemB = new Point((item.Center.X + (item.ActualWidth / 2)), (item.Center.Y - (item.ActualHeight / 2)));
                                Point itemC = new Point((item.Center.X + (item.ActualWidth / 2)), (item.Center.Y + (item.ActualHeight / 2)));
                                Point itemD = new Point((item.Center.X - (item.ActualWidth / 2)), (item.Center.Y + (item.ActualHeight / 2)));

                                // get the position of the rotated control with some math calculation
                                Point itemA1 = itemA.GetRotatedPoint(item.Orientation, item.ActualWidth, item.ActualHeight);
                                Point itemB1 = itemB.GetRotatedPoint(item.Orientation, item.ActualWidth, item.ActualHeight);
                                Point itemC1 = itemC.GetRotatedPoint(item.Orientation, item.ActualWidth, item.ActualHeight);
                                Point itemD1 = itemD.GetRotatedPoint(item.Orientation, item.ActualWidth, item.ActualHeight);


                                if (r1.Contains(itemA1) || r1.Contains(itemB1) || r1.Contains(itemC1) || r1.Contains(itemD1))
                                {
                                    //got it!
                                    string uri = (string)((Content)item.Content).DataContext;
                                    if (string.IsNullOrEmpty(uri) == false)
                                    {
                                        HostService.SendImage(e.ImageId, Serializer.FileToByteArray(uri));
                                    }

                                    // for this sample I evaluate only the first item contained, in a production application I would evaluate the position of the touchdown on the device
                                    // with the position of the items (if there is more than one) under the device..
                                    break;
                                }
                            }
                        }
                    }));

        }

        #region surface handlers
        /// <summary>
        /// Adds handlers for window availability events.
        /// </summary>
        private void AddWindowAvailabilityHandlers()
        {
            // Subscribe to surface window availability events
            ApplicationServices.WindowInteractive += OnWindowInteractive;
            ApplicationServices.WindowNoninteractive += OnWindowNoninteractive;
            ApplicationServices.WindowUnavailable += OnWindowUnavailable;
        }

        /// <summary>
        /// Removes handlers for window availability events.
        /// </summary>
        private void RemoveWindowAvailabilityHandlers()
        {
            // Unsubscribe from surface window availability events
            ApplicationServices.WindowInteractive -= OnWindowInteractive;
            ApplicationServices.WindowNoninteractive -= OnWindowNoninteractive;
            ApplicationServices.WindowUnavailable -= OnWindowUnavailable;
        }

        /// <summary>
        /// This is called when the user can interact with the application's window.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnWindowInteractive(object sender, EventArgs e)
        {
            HostService.StartSerivceHosts();
        }

        /// <summary>
        /// This is called when the user can see but not interact with the application's window.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnWindowNoninteractive(object sender, EventArgs e)
        {
            HostService.StopSerivceHosts();
        }

        /// <summary>
        /// This is called when the application's window is not visible or interactive.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnWindowUnavailable(object sender, EventArgs e)
        {
            HostService.StopSerivceHosts();
        }
        #endregion
    }
}